home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 03 - 1987 / 03.03 Mar 87 / Pascal Graf3D / Three-D Main < prev    next >
Encoding:
Text File  |  1987-02-15  |  14.5 KB  |  507 lines  |  [TEXT/PJMM]

  1. {********************}
  2. {    Graf3D Demo                     }
  3. {                                    }
  4. {    by Scott Berfield                }
  5. {    for MacTutor magazine        }
  6. {                                    }
  7. {********************}
  8.  
  9. PROGRAM ThreeDDemo;
  10.  
  11. {$I-}
  12.  
  13.     USES
  14.         Graf3D, FixMath;
  15. {MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, fixmath, graf3d}
  16.  
  17.     CONST
  18.         object = 1;    {flag indicating which we are currently rotating}
  19.         world = 2;
  20.         hellfreezesover = false;        {A never-changing boolean for eventloop}
  21.         VIEWwindowID = 32000;        {ID of our drawing window}
  22.         INPUTWINDOWID = 32001;    {ID of our control window}
  23.         APPLEM = 0;                    {Menu indices}
  24.         FILEM = 1;
  25.         EDITM = 2;
  26.         SWITCHM = 3;
  27.         appleID = 128;                {Menu resource IDs}
  28.         fileID = 129;
  29.         editID = 130;
  30.         SWITCHID = 131;
  31.         lastmenu = 3;                    {How many menus}
  32.         aboutID = 128;                {About alert resource ID}
  33.         UndoItem = 1;                    {Menu item codes}
  34.         cutitem = 3;
  35.         copyitem = 4;
  36.         pasteitem = 5;
  37.         clearitem = 6;
  38.         XScrollID = 128;                {Scroll bar resource IDs}
  39.         YScrollID = 129;
  40.         ZScrollID = 130;
  41.         XMIN = -200;                    {Limits for object space (set with LOOKAT)}
  42.         YMIN = -200;
  43.         ZMIN = -200;
  44.         XMAX = 200;
  45.         YMAX = 200;
  46.         ZMAX = 200;
  47.  
  48.     VAR
  49.         fromupdate : boolean;
  50.         whichcontrol : controlhandle;                        {which control was hit?}
  51.         xscroll, yscroll, zscroll : controlhandle;                {storage for scrollbars}
  52.         myMenus : ARRAY[0..lastmenu] OF menuhandle;    {our menus}
  53.         INPUTWINDOW : windowptr;                        {pointers to our windows}
  54.         VIEWWindow : windowPtr;
  55.         Wrecord : windowrecord;                            {Storage for our windows}
  56.         Wrecord2 : windowrecord;
  57.         gport3d : port3d;                                    {Our 3D grafport}
  58.         XROT, YROT, ZROT : integer;                        {current scrollbar settings}
  59.         OXROT, OYROT, OZROT : integer;                    {old scroll bar settings}
  60.         which : integer;                                        {Object or world rotation?}
  61.         XSpacerot, YSpaceRot, ZSpaceRot : integer;        {how much is space rotated?}
  62.         XObjRot, YObjRot, ZObjRot : integer;                {how much is the object rotated?}
  63.         Dtetra, tetra : ARRAY[1..4] OF point3d;                {the original and the transformed tetrahedra}
  64.         delta : integer;                                         {inc or dec the scroll bars}
  65.  
  66. {------ crash --------}
  67.     PROCEDURE crash;
  68.     BEGIN
  69.         exittoshell;
  70.     END;
  71.  
  72. { --------- init ---------}
  73.     PROCEDURE init;    {set everything up}
  74.     BEGIN
  75.         initgraf(@thePort);
  76.         initgrf3d(@theport3d);    {this is the graf3D equivalent. It IS NOT optional}
  77.         InitFonts;
  78.         InitWindows;
  79.         InitMenus;
  80.         TEInit;
  81.         InitDialogs(@crash);
  82.         InitCursor;
  83.         FlushEvents(everyEvent, 0);
  84.  
  85.         XROT := 0;            {Set initial values for everything}
  86.         YROT := 0;
  87.         ZROT := 0;
  88.         OXROT := 1;
  89.         OYROT := 1;
  90.         OZROT := 1;
  91.         XSpaceRot := 0;
  92.         YSpaceRot := 0;
  93.         ZSpaceRot := 0;
  94.         XObjRot := 0;
  95.         YObjRot := 0;
  96.         ZObjRot := 0;
  97.         which := object;        {the default is to rotate the object}
  98.         setpt3d(tetra[1], 0, -6553600, 0); {set the tetrahedron's vertices}
  99.         setpt3d(tetra[2], -1638400, -3276800, 0);
  100.         setpt3d(tetra[3], 1638400, -3276800, 0);
  101.         setpt3d(tetra[4], 0, -4915200, 1638400);
  102.         DTetra := tetra;
  103.     END;                 {init}
  104.  
  105.     PROCEDURE drawvalues;        {Draw the current scroll bar settings as text}
  106.         VAR
  107.             text1, text2, text3 : str255;
  108.             trect : rect;
  109.     BEGIN
  110.         IF (OXROT <> XROT) OR (OYROT <> YROT) OR (OZROT <> ZROT) OR (fromupdate) THEN
  111.             BEGIN                                        {we only draw them if only if something has changed}
  112.                 setrect(trect, 0, 45, 512, 65);
  113.                 setport(inputwindow);
  114.                 eraserect(trect);
  115.                 penpat(black);
  116.                 textfont(0);
  117.                 textsize(12);
  118.                 numtostring(xrot, text1);
  119.                 numtostring(yrot, text2);
  120.                 numtostring(zrot, text3);
  121.                 moveto(10, 55);
  122.                 drawstring(text1);
  123.                 moveto(175, 55);
  124.                 drawstring(text2);
  125.                 moveto(340, 55);
  126.                 drawstring(text3);
  127.                 OXROT := XROT;
  128.                 OYROT := YROT;
  129.                 OZROT := ZROT;
  130.             END;
  131.     END;                 {drawvalues}
  132.  
  133.     PROCEDURE drawlabels;    {label the scroll bars}
  134.         VAR
  135.             labelrect : rect;
  136.     BEGIN
  137.         setrect(labelrect, 0, 0, 512, 24);
  138.         setport(inputwindow);
  139.         eraserect(labelrect);
  140.         textfont(0);        {Chicago font}
  141.         textsize(12);        {12 point}
  142.         penpat(black);    {make sure we can see it}
  143.         CASE which OF    {which labels do we draw?}
  144.             object : 
  145.                 BEGIN
  146.                     moveto(10, 19);
  147.                     drawstring('X Rotation');
  148.                     moveto(175, 19);
  149.                     drawstring('Y Rotation');
  150.                     moveto(340, 19);
  151.                     drawstring('Z Rotation');
  152.                 END;
  153.             world : 
  154.                 BEGIN
  155.                     moveto(10, 19);
  156.                     drawstring('Pitch');
  157.                     moveto(175, 19);
  158.                     drawstring('Yaw');
  159.                     moveto(340, 19);
  160.                     drawstring('Roll');
  161.                 END;
  162.         END;
  163.     END;            {drawlabels}
  164.  
  165.     PROCEDURE drawgrid;        {Draw the “space grid”}
  166.         VAR
  167.             i : integer;
  168.     BEGIN                                {all coordinates must be in fixed point — multiply by 65536}
  169.         pitch(XSPACEROT * 65536);    {rotate space by x value...}
  170.         YAW(YSPACEROT * 65536);    {rotate space by y value...}
  171.         ROLL(ZSPACEROT * 65536);    {rotate space by z value...}
  172. {now draw the grid in the newly rotated space}
  173.         moveto3d(-6553600, 0, -6553600);         {-100,0,-100}
  174.         lineto3d(-6553600, 0, 6553600);            {etc...}
  175.         lineto3d(6553600, 0, 6553600);
  176.         lineto3d(6553600, 0, -6553600);
  177.         lineto3d(-6553600, 0, -6553600);
  178.         moveto3d(0, 0, -6553600);
  179.         lineto3d(0, 0, 6553600);
  180.         moveto3d(-6553600, 0, 0);
  181.         lineto3d(6553600, 0, 0);
  182. {when we leave (to go back to procedure drawview) space is still rotated}
  183.     END;                                {drawgrid}
  184.  
  185.     PROCEDURE drawtetra;    {draw our object}
  186.     BEGIN
  187.         moveto3d(Dtetra[1].x, Dtetra[1].y, Dtetra[1].z);    {we draw using the DTetra array which}
  188.         lineto3d(Dtetra[2].x, Dtetra[2].y, Dtetra[2].z);        {holds the transformed coordinates}
  189.         lineto3d(Dtetra[3].x, Dtetra[3].y, Dtetra[3].z);        {Note that point3D's are already in}
  190.         lineto3d(Dtetra[1].x, Dtetra[1].y, Dtetra[1].z);        {fixed - point }
  191.         lineto3d(Dtetra[4].x, Dtetra[4].y, Dtetra[4].z);
  192.         moveto3d(Dtetra[2].x, Dtetra[2].y, Dtetra[2].z);
  193.         lineto3d(Dtetra[4].x, Dtetra[4].y, Dtetra[4].z);
  194.         lineto3d(Dtetra[3].x, Dtetra[3].y, Dtetra[3].z);
  195.     END;                        {drawtetra}
  196.  
  197.     PROCEDURE drawview;    {draw the contents of the view window using current transform matrix}
  198.     BEGIN
  199.         setport(viewwindow);    {where we need to be to draw}
  200.         penpat(black);            {eraser color}
  201.         paintrect(theport^.portrect);    {erase the screen}
  202.         penpat(white);            {line color}
  203.         drawgrid;                    {draw the plane — space has been rotated when we return}
  204.         drawtetra;                {draw the object}
  205.         identity;                    {reset the transform matrix so we can figure next setting}
  206.         setport(inputwindow);    {Back to the control window for more scroll bar action!}
  207.     END;                            {Drawview}
  208.  
  209.     PROCEDURE drawinput;    {Draw the control window}
  210.     BEGIN
  211.         setport(inputwindow);
  212.         drawvalues;
  213.         drawlabels;
  214.         Drawcontrols(inputwindow);
  215.     END;                            {drawinput}
  216.  
  217.     PROCEDURE TRANS;    {transformation based on current scroll bar settings}
  218.         VAR
  219.             i : integer;
  220.     BEGIN
  221.         PITCH(XROT * 65536);    {x rotation}
  222.         YAW(YROT * 65536);    {y rotation}
  223.         ROLL(ZROT * 65536);    {z rotation}
  224.         IF which = object THEN    {if we are rotating the object...}
  225.             FOR i := 1 TO 4 DO
  226.                 BEGIN
  227.                     transform(tetra[i], Dtetra[i]);    {we apply the matrix to each point in the virgin tetra and}
  228.                 END;                                    {store it in the drawing tetra}
  229.         identity;                    {in any case, we reset the matrix before we draw the window}
  230.         drawview;                {so that the drawview procedure can control the global viewpoint}
  231.     END;                {TRANS}
  232.  
  233.  
  234.     PROCEDURE updateRots;    {update values from scroll bars}
  235.     BEGIN
  236.         XROT := GETCTLVALUE(XSCROLL);    {get the current values}
  237.         YROT := GETCTLVALUE(YSCROLL);
  238.         ZROT := GETCTLVALUE(ZSCROLL);
  239.         DrawValues;                            {draw them}
  240.         CASE which OF
  241.             object :                                 {which values need updating?}
  242.                 BEGIN
  243.                     XObjRot := XROT;
  244.                     YOBJROT := YROT;
  245.                     ZOBJROT := ZROT;
  246.                     TRANS;
  247.                 END;
  248.             world : 
  249.                 BEGIN
  250.                     XspaceRot := XROT;
  251.                     YspaceROT := YROT;
  252.                     ZspaceROT := ZROT;
  253.                     drawview;
  254.                 END;
  255.         END;
  256.     END;                    {updaterots}
  257.  
  258.  
  259.     PROCEDURE dowindows;        {set up the windows and the 3D stuff}
  260.         VAR
  261.             Vrect : rect;
  262.     BEGIN
  263.         InputWindow := GetNewWindow(INPUTWINDOWID, @Wrecord2, POINTER(-1));
  264.         xScroll := GetNewControl(XScrollID, InputWindow);
  265.         yScroll := GetNewControl(YScrollID, InputWindow);
  266.         zScroll := GetNewControl(ZScrollID, InputWindow);
  267.         ViewWindow := GetNewWindow(VIEWWINDOWID, @Wrecord, POINTER(-1));
  268. {set up a 3D grafport (it uses the reg. grafport for drawing}
  269.         Open3DPort(@gPort3D);
  270.         setport3d(@gPort3d);
  271.         viewport(viewwindow^.portbits.bounds);    {set the drawing area to the full window}
  272.         lookat(XMIN * 65536, YMIN * 65536, XMAX * 65536, YMAX * 65536);    {set the image space}
  273. {set the angle… 25° = human field of view.  0°=no persp.  80°=fish-eye lens}
  274.         viewangle(1638400);     {25° * 65536}
  275.     END;                            {doWindows}
  276.  
  277.  
  278.     PROCEDURE domenus;    {set up menus}
  279.         VAR
  280.             i : integer;
  281.     BEGIN
  282.         myMenus[appleM] := GetMenu(appleID);
  283.         AddResMenu(myMenus[appleM], 'DRVR');
  284.         myMenus[FileM] := GetMenu(fileID);
  285.         myMenus[EditM] := GetMenu(editID);
  286.         mymenus[SwitchM] := GetMenu(switchID);
  287.         FOR i := appleM TO lastmenu DO
  288.             insertMenu(myMenus[i], 0);
  289.         SetItemIcon(myMenus[0], 1, 195);
  290.         DrawMenuBar;
  291.     END;        {doMenus}
  292.  
  293.     PROCEDURE aboutme;    {do about box}
  294.         VAR
  295.             foo : integer;
  296.     BEGIN
  297.         foo := alert(aboutID, NIL);
  298.     END;        {aboutme}
  299.  
  300.  
  301.     PROCEDURE applfile (theItem : integer);        {handle file menu}
  302.     BEGIN
  303.         exittoshell;        {they chose Quit}
  304.     END;            {applfile}
  305.  
  306.     PROCEDURE DoCommand (theCommand : LongInt);    {handle menu choices}
  307.         VAR
  308.             theMenu, theItem : integer;
  309.             name : str255;
  310.             RefNum : integer;
  311.             dum : integer;
  312.             blah : boolean;
  313.     BEGIN
  314.         theMenu := hiWord(theCommand);
  315.         theItem := loWord(theCommand);
  316.         CASE theMenu OF
  317.             AppleID : 
  318.                 BEGIN
  319.                     IF (theItem = 1) THEN
  320.                         AboutMe                                                {about box}
  321.                     ELSE
  322.                         BEGIN
  323.                             getItem(myMenus[appleM], theItem, name);        {selected a desk accessory}
  324.                             dum := OpenDeskAcc(Name)
  325.                         END;         {else}
  326.                 END;             {appleM}
  327.  
  328.             FileID : 
  329.                 ApplFile(theItem);
  330.  
  331.             EditID : 
  332.                 blah := systemEdit(theItem - 1);
  333.  
  334.             SwitchID : 
  335.                 BEGIN
  336.                     CASE which OF            {adjust menuand controls to reflect which we are rotating now}
  337.                         object :                 {we were rotating the object, now we switch to rotating space}
  338.                             BEGIN
  339.                                 which := world;
  340.                                 setitem(mymenus[switchM], 1, 'Rotate Object');
  341.                                 setport(inputwindow);
  342.                                 drawlabels;
  343.                                 setctlvalue(xscroll, xspacerot);    {pick up the settings from the space values}
  344.                                 setctlvalue(yscroll, yspacerot);
  345.                                 setctlvalue(zscroll, zspacerot);
  346.                                 xrot := xspacerot;                    {update our holders}
  347.                                 yrot := yspacerot;
  348.                                 zrot := zspacerot;
  349.                                 drawvalues;                            {draw the values for the scroll bars}
  350.                             END;                        {object case}
  351.                         world : 
  352.                             BEGIN                    {switching from world to object rotations}
  353.                                 which := object;
  354.                                 setitem(mymenus[switchM], 1, 'Rotate Space');
  355.                                 setport(inputwindow);
  356.                                 drawlabels;
  357.                                 setctlvalue(xscroll, xobjrot);
  358.                                 setctlvalue(yscroll, yobjrot);
  359.                                 setctlvalue(zscroll, zobjrot);
  360.                                 xrot := xobjrot;
  361.                                 yrot := yobjrot;
  362.                                 zrot := zobjrot;
  363.                                 drawvalues;
  364.                             END;                    {world case}
  365.                         OTHERWISE
  366.                     END;            {case which of}
  367.                 END;    {switch menu case}
  368.             OTHERWISE
  369.         END;     {case theMenu}
  370.         hiliteMenu(0);    {turn off menu hilight}
  371.     END; {doCommand}
  372.  
  373.     PROCEDURE changearrow;
  374.     BEGIN
  375.         setctlvalue(whichcontrol, getctlvalue(whichcontrol) + delta);
  376.         updaterots;
  377.     END;
  378.  
  379.     PROCEDURE ApplMouseDown (theWindow : windowPtr;
  380.                                     MousePoint : point);        {handle scroll bars}
  381.         VAR
  382.             partcode : integer;
  383.             dummy, temp : integer;
  384.     BEGIN
  385.         IF theWindow = inputwindow THEN
  386.             BEGIN
  387.                 setport(inputwindow);
  388.                 globaltolocal(mousepoint);
  389.                 partcode := findcontrol(mousepoint, theWindow, whichcontrol);
  390.                 CASE partcode OF
  391.                     inupbutton : 
  392.                         BEGIN
  393.                             delta := -1;
  394.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  395.                         END;
  396.                     indownbutton : 
  397.                         BEGIN
  398.                             delta := 1;
  399.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  400.                         END;
  401.                     inpageup : 
  402.                         BEGIN
  403.                             delta := -10;
  404.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  405.                         END;
  406.                     inpagedown : 
  407.                         BEGIN
  408.                             delta := 10;
  409.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  410.                         END;
  411.                     inthumb : 
  412.                         BEGIN
  413.                             temp := getctlvalue(whichcontrol);
  414.                             dummy := trackcontrol(whichcontrol, mousepoint, NIL);
  415.                             IF getctlvalue(whichcontrol) <> temp THEN
  416.                                 updaterots;
  417.                         END;
  418.                     OTHERWISE
  419.                 END;    {case partcode of}
  420.             END;        {if}
  421.     END;         {applMouseDown}
  422.  
  423.  
  424.     PROCEDURE DoKeyDown (Event : EventRecord);        {they pressed a key}
  425.         VAR
  426.             CharCode : char;
  427.     BEGIN
  428.         CharCode := chr(Event.message MOD 256);
  429.         IF BitAnd(Event.modifiers, CmdKey) = CmdKey THEN        {must of been a command key, right?}
  430.             DoCommand(MenuKey(CharCode))                            {pass it to menu handler}
  431.     END;  { DoKeyDown }
  432.  
  433.     PROCEDURE EventLoop;        {the meat of the Mac application — process those events!}
  434.         VAR
  435.             saveport : GrafPtr;
  436.             GotEvent : boolean;
  437.             NewEvent : EventRecord;
  438.             WhichWindow : WindowPtr;
  439.             Key : char;
  440.             KeyCommand : LongInt;
  441.     BEGIN
  442.         flushevents(everyevent, 0);
  443.         REPEAT
  444.             GotEvent := GetNextEvent(EveryEvent, NewEvent);
  445.             IF GotEvent THEN
  446.                 BEGIN
  447.                     CASE NewEvent.What OF
  448.                         mouseDown : 
  449.                             BEGIN
  450.                                 CASE FindWindow(NewEvent.where, whichWindow) OF
  451.                                     inMenuBar : 
  452.                                         doCommand(menuSelect(NewEvent.where));
  453.                                     inSysWindow : 
  454.                                         SystemClick(newEvent, whichWindow);
  455.                                     inContent : 
  456.                                         applMouseDown(whichWindow, NewEvent.where); {case inContent}
  457.                                     inGoAway : 
  458.                                         IF TrackGoAway(whichWindow, NewEvent.Where) THEN
  459.                                             BEGIN
  460.                                                 ExitToShell;
  461.                                             END;
  462.                                     inDrag : 
  463.                                         IF whichWindow <> FrontWindow THEN
  464.                                             SelectWindow(whichWindow)
  465.                                         ELSE
  466.                                             applMouseDown(whichWindow, NewEvent.where);
  467.                                     OTHERWISE
  468.                                 END; {case FWReturnCode}
  469.                             END; {case mouseDown}
  470.  
  471.                         KeyDown : 
  472.                             BEGIN
  473.                                 doKeyDown(newEvent);
  474.                             END; {Case KeyDown}
  475.  
  476.                         UpdateEvt : 
  477.                             BEGIN
  478.                                 getport(saveport);            {store current grafport}
  479.                                 setport(viewwindow);        {set it to the viewwindow}
  480.                                 beginupdate(viewwindow);
  481.                                 drawview;
  482.                                 endupdate(viewwindow);
  483.                                 setport(inputwindow);        {now do the control window}
  484.                                 beginupdate(inputwindow);
  485.                                 fromupdate := true;            {used to draw the values if needed}
  486.                                 drawinput;
  487.                                 fromupdate := false;            {reset the toggle}
  488.                                 endupdate(inputwindow);
  489.                                 setport(saveport);            {restore the port}
  490.                             END;     {updateEvt}
  491.                         OTHERWISE
  492.                     END;     {NewEvent.What}
  493.                 END;     {if}
  494.             systemTask;    {handle periodic stuff}
  495.         UNTIL HellFreezesOver;    {let it run for a good long time}
  496.     END; {EventLoop}
  497.  
  498. { ---------- Main Program ----------------}
  499. BEGIN
  500.     init;                {Init all toolbox stuff as well as application variables}
  501.     dowindows;        {draw the windows and setup 3D grafport}
  502.     domenus;        {do the menus}
  503.     identity;            {reset the transformation matrix (just in case)}
  504.     drawview;        {draw the contents of the view window}
  505.     drawinput;        {draw the contents of the control window}
  506.     eventloop;        {Handle the events}
  507. END.            {That's all for now…}